home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / progs / sviluppo / python-1.4 / lib / htmllib.py < prev    next >
Text File  |  1996-11-24  |  10KB  |  429 lines

  1. """HTML 2.0 parser.
  2.  
  3. See the HTML 2.0 specification:
  4. http://www.w3.org/hypertext/WWW/MarkUp/html-spec/html-spec_toc.html
  5. """
  6.  
  7.  
  8. import sys
  9. import regsub
  10. import string
  11. from sgmllib import SGMLParser
  12. from formatter import AS_IS
  13.  
  14.  
  15. class HTMLParser(SGMLParser):
  16.  
  17.     from htmlentitydefs import entitydefs
  18.  
  19.     def __init__(self, formatter, verbose=0):
  20.         SGMLParser.__init__(self, verbose)
  21.         self.formatter = formatter
  22.         self.savedata = None
  23.         self.isindex = 0
  24.         self.title = None
  25.         self.base = None
  26.         self.anchor = None
  27.         self.anchorlist = []
  28.         self.nofill = 0
  29.         self.list_stack = []
  30.  
  31.     # ------ Methods used internally; some may be overridden
  32.  
  33.     # --- Formatter interface, taking care of 'savedata' mode;
  34.     # shouldn't need to be overridden
  35.  
  36.     def handle_data(self, data):
  37.         if self.savedata is not None:
  38.         self.savedata = self.savedata + data
  39.         else:
  40.         if self.nofill:
  41.         self.formatter.add_literal_data(data)
  42.         else:
  43.         self.formatter.add_flowing_data(data)
  44.  
  45.     # --- Hooks to save data; shouldn't need to be overridden
  46.  
  47.     def save_bgn(self):
  48.         self.savedata = ''
  49.  
  50.     def save_end(self):
  51.         data = self.savedata
  52.         self.savedata = None
  53.     if not self.nofill:
  54.         data = string.join(string.split(data))
  55.     return data
  56.  
  57.     # --- Hooks for anchors; should probably be overridden
  58.  
  59.     def anchor_bgn(self, href, name, type):
  60.         self.anchor = href
  61.         if self.anchor:
  62.         self.anchorlist.append(href)
  63.  
  64.     def anchor_end(self):
  65.         if self.anchor:
  66.         self.handle_data("[%d]" % len(self.anchorlist))
  67.         self.anchor = None
  68.  
  69.     # --- Hook for images; should probably be overridden
  70.  
  71.     def handle_image(self, src, alt, *args):
  72.         self.handle_data(alt)
  73.  
  74.     # --------- Top level elememts
  75.  
  76.     def start_html(self, attrs): pass
  77.     def end_html(self): pass
  78.  
  79.     def start_head(self, attrs): pass
  80.     def end_head(self): pass
  81.  
  82.     def start_body(self, attrs): pass
  83.     def end_body(self): pass
  84.  
  85.     # ------ Head elements
  86.  
  87.     def start_title(self, attrs):
  88.         self.save_bgn()
  89.  
  90.     def end_title(self):
  91.         self.title = self.save_end()
  92.  
  93.     def do_base(self, attrs):
  94.         for a, v in attrs:
  95.             if a == 'href':
  96.                 self.base = v
  97.  
  98.     def do_isindex(self, attrs):
  99.         self.isindex = 1
  100.  
  101.     def do_link(self, attrs):
  102.         pass
  103.  
  104.     def do_meta(self, attrs):
  105.         pass
  106.  
  107.     def do_nextid(self, attrs): # Deprecated
  108.         pass
  109.  
  110.     # ------ Body elements
  111.  
  112.     # --- Headings
  113.  
  114.     def start_h1(self, attrs):
  115.         self.formatter.end_paragraph(1)
  116.         self.formatter.push_font(('h1', 0, 1, 0))
  117.  
  118.     def end_h1(self):
  119.         self.formatter.end_paragraph(1)
  120.         self.formatter.pop_font()
  121.  
  122.     def start_h2(self, attrs):
  123.         self.formatter.end_paragraph(1)
  124.         self.formatter.push_font(('h2', 0, 1, 0))
  125.  
  126.     def end_h2(self):
  127.         self.formatter.end_paragraph(1)
  128.         self.formatter.pop_font()
  129.  
  130.     def start_h3(self, attrs):
  131.         self.formatter.end_paragraph(1)
  132.         self.formatter.push_font(('h3', 0, 1, 0))
  133.  
  134.     def end_h3(self):
  135.         self.formatter.end_paragraph(1)
  136.         self.formatter.pop_font()
  137.  
  138.     def start_h4(self, attrs):
  139.         self.formatter.end_paragraph(1)
  140.         self.formatter.push_font(('h4', 0, 1, 0))
  141.  
  142.     def end_h4(self):
  143.         self.formatter.end_paragraph(1)
  144.         self.formatter.pop_font()
  145.  
  146.     def start_h5(self, attrs):
  147.         self.formatter.end_paragraph(1)
  148.         self.formatter.push_font(('h5', 0, 1, 0))
  149.  
  150.     def end_h5(self):
  151.         self.formatter.end_paragraph(1)
  152.         self.formatter.pop_font()
  153.  
  154.     def start_h6(self, attrs):
  155.         self.formatter.end_paragraph(1)
  156.         self.formatter.push_font(('h6', 0, 1, 0))
  157.  
  158.     def end_h6(self):
  159.         self.formatter.end_paragraph(1)
  160.         self.formatter.pop_font()
  161.  
  162.     # --- Block Structuring Elements
  163.  
  164.     def do_p(self, attrs):
  165.         self.formatter.end_paragraph(1)
  166.  
  167.     def start_pre(self, attrs):
  168.         self.formatter.end_paragraph(1)
  169.         self.formatter.push_font((AS_IS, AS_IS, AS_IS, 1))
  170.         self.nofill = self.nofill + 1
  171.  
  172.     def end_pre(self):
  173.         self.formatter.end_paragraph(1)
  174.         self.formatter.pop_font()
  175.         self.nofill = max(0, self.nofill - 1)
  176.  
  177.     def start_xmp(self, attrs):
  178.         self.start_pre(attrs)
  179.         self.setliteral('xmp') # Tell SGML parser
  180.  
  181.     def end_xmp(self):
  182.         self.end_pre()
  183.  
  184.     def start_listing(self, attrs):
  185.         self.start_pre(attrs)
  186.         self.setliteral('listing') # Tell SGML parser
  187.  
  188.     def end_listing(self):
  189.         self.end_pre()
  190.  
  191.     def start_address(self, attrs):
  192.         self.formatter.end_paragraph(0)
  193.         self.formatter.push_font((AS_IS, 1, AS_IS, AS_IS))
  194.  
  195.     def end_address(self):
  196.         self.formatter.end_paragraph(0)
  197.         self.formatter.pop_font()
  198.  
  199.     def start_blockquote(self, attrs):
  200.         self.formatter.end_paragraph(1)
  201.         self.formatter.push_margin('blockquote')
  202.  
  203.     def end_blockquote(self):
  204.         self.formatter.end_paragraph(1)
  205.         self.formatter.pop_margin()
  206.  
  207.     # --- List Elements
  208.  
  209.     def start_ul(self, attrs):
  210.         self.formatter.end_paragraph(not self.list_stack)
  211.         self.formatter.push_margin('ul')
  212.         self.list_stack.append(['ul', '*', 0])
  213.  
  214.     def end_ul(self):
  215.         if self.list_stack: del self.list_stack[-1]
  216.         self.formatter.end_paragraph(not self.list_stack)
  217.         self.formatter.pop_margin()
  218.  
  219.     def do_li(self, attrs):
  220.         self.formatter.end_paragraph(0)
  221.         if self.list_stack:
  222.         [dummy, label, counter] = top = self.list_stack[-1]
  223.         top[2] = counter = counter+1
  224.         else:
  225.         label, counter = '*', 0
  226.         self.formatter.add_label_data(label, counter)
  227.  
  228.     def start_ol(self, attrs):
  229.         self.formatter.end_paragraph(not self.list_stack)
  230.         self.formatter.push_margin('ol')
  231.         label = '1.'
  232.         for a, v in attrs:
  233.             if a == 'type':
  234.         if len(v) == 1: v = v + '.'
  235.         label = v
  236.         self.list_stack.append(['ol', label, 0])
  237.  
  238.     def end_ol(self):
  239.         if self.list_stack: del self.list_stack[-1]
  240.         self.formatter.end_paragraph(not self.list_stack)
  241.         self.formatter.pop_margin()
  242.  
  243.     def start_menu(self, attrs):
  244.         self.start_ul(attrs)
  245.  
  246.     def end_menu(self):
  247.         self.end_ul()
  248.  
  249.     def start_dir(self, attrs):
  250.         self.start_ul(attrs)
  251.  
  252.     def end_dir(self):
  253.         self.end_ul()
  254.  
  255.     def start_dl(self, attrs):
  256.         self.formatter.end_paragraph(1)
  257.         self.list_stack.append(['dl', '', 0])
  258.  
  259.     def end_dl(self):
  260.         self.ddpop(1)
  261.         if self.list_stack: del self.list_stack[-1]
  262.  
  263.     def do_dt(self, attrs):
  264.         self.ddpop()
  265.  
  266.     def do_dd(self, attrs):
  267.         self.ddpop()
  268.         self.formatter.push_margin('dd')
  269.         self.list_stack.append(['dd', '', 0])
  270.  
  271.     def ddpop(self, bl=0):
  272.         self.formatter.end_paragraph(bl)
  273.         if self.list_stack:
  274.             if self.list_stack[-1][0] == 'dd':
  275.         del self.list_stack[-1]
  276.         self.formatter.pop_margin()
  277.  
  278.     # --- Phrase Markup
  279.  
  280.     # Idiomatic Elements
  281.  
  282.     def start_cite(self, attrs): self.start_i(attrs)
  283.     def end_cite(self): self.end_i()
  284.  
  285.     def start_code(self, attrs): self.start_tt(attrs)
  286.     def end_code(self): self.end_tt()
  287.  
  288.     def start_em(self, attrs): self.start_i(attrs)
  289.     def end_em(self): self.end_i()
  290.  
  291.     def start_kbd(self, attrs): self.start_tt(attrs)
  292.     def end_kbd(self): self.end_tt()
  293.  
  294.     def start_samp(self, attrs): self.start_tt(attrs)
  295.     def end_samp(self): self.end_tt()
  296.  
  297.     def start_strong(self, attrs): self.start_b(attrs)
  298.     def end_strong(self): self.end_b()
  299.  
  300.     def start_var(self, attrs): self.start_i(attrs)
  301.     def end_var(self): self.end_i()
  302.  
  303.     # Typographic Elements
  304.  
  305.     def start_i(self, attrs):
  306.     self.formatter.push_font((AS_IS, 1, AS_IS, AS_IS))
  307.     def end_i(self):
  308.     self.formatter.pop_font()
  309.  
  310.     def start_b(self, attrs):
  311.     self.formatter.push_font((AS_IS, AS_IS, 1, AS_IS))
  312.     def end_b(self):
  313.     self.formatter.pop_font()
  314.  
  315.     def start_tt(self, attrs):
  316.     self.formatter.push_font((AS_IS, AS_IS, AS_IS, 1))
  317.     def end_tt(self):
  318.     self.formatter.pop_font()
  319.  
  320.     def start_a(self, attrs):
  321.         href = ''
  322.         name = ''
  323.         type = ''
  324.         for attrname, value in attrs:
  325.         value = string.strip(value)
  326.             if attrname == 'href':
  327.                 href = value
  328.             if attrname == 'name':
  329.                 name = value
  330.             if attrname == 'type':
  331.                 type = string.lower(value)
  332.         self.anchor_bgn(href, name, type)
  333.  
  334.     def end_a(self):
  335.         self.anchor_end()
  336.  
  337.     # --- Line Break
  338.  
  339.     def do_br(self, attrs):
  340.         self.formatter.add_line_break()
  341.  
  342.     # --- Horizontal Rule
  343.  
  344.     def do_hr(self, attrs):
  345.         self.formatter.add_hor_rule()
  346.  
  347.     # --- Image
  348.  
  349.     def do_img(self, attrs):
  350.         align = ''
  351.         alt = '(image)'
  352.         ismap = ''
  353.         src = ''
  354.     width = 0
  355.     height = 0
  356.         for attrname, value in attrs:
  357.             if attrname == 'align':
  358.                 align = value
  359.             if attrname == 'alt':
  360.                 alt = value
  361.             if attrname == 'ismap':
  362.                 ismap = value
  363.             if attrname == 'src':
  364.                 src = value
  365.         if attrname == 'width':
  366.         try: width = string.atoi(value)
  367.         except: pass
  368.         if attrname == 'height':
  369.         try: height = string.atoi(value)
  370.         except: pass
  371.         self.handle_image(src, alt, ismap, align, width, height)
  372.  
  373.     # --- Really Old Unofficial Deprecated Stuff
  374.  
  375.     def do_plaintext(self, attrs):
  376.         self.start_pre(attrs)
  377.         self.setnomoretags() # Tell SGML parser
  378.  
  379.     # --- Unhandled tags
  380.  
  381.     def unknown_starttag(self, tag, attrs):
  382.         pass
  383.  
  384.     def unknown_endtag(self, tag):
  385.         pass
  386.  
  387.  
  388. def test(args = None):
  389.     import sys, formatter
  390.  
  391.     if not args:
  392.     args = sys.argv[1:]
  393.  
  394.     silent = args and args[0] == '-s'
  395.     if silent:
  396.     del args[0]
  397.  
  398.     if args:
  399.     file = args[0]
  400.     else:
  401.     file = 'test.html'
  402.  
  403.     if file == '-':
  404.     f = sys.stdin
  405.     else:
  406.     try:
  407.         f = open(file, 'r')
  408.     except IOError, msg:
  409.         print file, ":", msg
  410.         sys.exit(1)
  411.  
  412.     data = f.read()
  413.  
  414.     if f is not sys.stdin:
  415.     f.close()
  416.     
  417.     if silent:
  418.     f = formatter.NullFormatter()
  419.     else:
  420.     f = formatter.AbstractFormatter(formatter.DumbWriter())
  421.  
  422.     p = HTMLParser(f)
  423.     p.feed(data)
  424.     p.close()
  425.  
  426.  
  427. if __name__ == '__main__':
  428.     test()
  429.